package com.yaolifei.flower.model.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Entity;
import org.nutz.dao.impl.DaoSupport;
import org.nutz.dao.impl.NutDao;
import org.nutz.dao.sql.Criteria;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.annotation.InjectName;
import org.nutz.ioc.loader.annotation.IocBean;

import com.yaolifei.flower.core.utils.Assert;
import com.yaolifei.flower.model.Model;
import com.yaolifei.flower.model.ModelColumn;
import com.yaolifei.flower.model.service.ModelService;
import com.yaolifei.flower.model.utils.ModelEntityMaker;

@IocBean(args={"refer:nutDao"})
@InjectName("modelService")
public class ModelImpl implements ModelService {

	private Dao dao;

	public ModelImpl(Dao dao) {
		this.dao = dao;
	}

	@Override
	public Model addModel(final Model model) {
		return dao.insert(model);
	}

	@Override
	public void deleteModel(int modelId) {
		Model model = getModel(modelId);
		Assert.notNull(model, "模型对象不存在！");

		// 删除物理表
		dao.drop(model.getPhysicalName());

		// 同时删除列
		dao.clear(ModelColumn.class, Cnd.where("modelId", "=", modelId));

		dao.delete(Model.class, modelId);
	}

	@Override
	public void updateModel(final Model model) {
		dao.update(model);
	}

	@Override
	public Model getModel(int modelId) {
		return dao.fetch(Model.class, modelId);
	}

	@Override
	public List<Model> getTopModels() {
		return dao.query(Model.class, Cnd.where("parentId", "=", 0));
	}

	@Override
	public List<Model> getChildren(int parentId) {
		return dao.query(Model.class, Cnd.where("parentId", "=", parentId));
	}

	@Override
	public void buildModelTable(int modelId) {
		Model model = getModel(modelId);
		buildModelTable(model);
	}

	@Override
	public void buildModelTable(Model model) {
		buildModelTable(model, false);
	}

	private void buildModelTable(Model model, boolean onlySystemColumn) {
		Assert.notNull(model, "模型对象不能为空！");

		List<ModelColumn> modelColumnList = new ArrayList<ModelColumn>();
		if (!onlySystemColumn) {
			modelColumnList.addAll(getModelColumnList(model.getModelId()));
			model.setColumns(modelColumnList);
			validateModel(model);
		}

		// 加入系统列
		modelColumnList.addAll(ModelColumn.SYSTEM_COLUMN);
		Collections.sort(modelColumnList);

		DaoSupport support = (NutDao) dao;
		ModelEntityMaker maker = new ModelEntityMaker(support);
		Entity<Object> entity = maker.makeNutEntity(model);
		support.getJdbcExpert().createEntity(dao, entity);

		model.setCreated(true);
		dao.update(model, "^created$");

		if (!onlySystemColumn) {
			dao.update(ModelColumn.class, Chain.make("created", true),
					Cnd.where("modelId", "=", model.getModelId()));
		}
	}

	private void validateModel(Model model) {
		Assert.isFalse(model.isCreated(), "模块表已经生成！");
		Assert.notNull(model.getPhysicalName(), "表名不能为空！");

		List<ModelColumn> modelColumnList = model.getColumns();
		for (ModelColumn column : modelColumnList) {
			validateModelColumn(column);
		}
	}

	private void validateModelColumn(ModelColumn column) {
		Assert.notNull(column.getPhysicalName(), "列【 " + column.getColumnName()
				+ "】物理名不能为空");
		Assert.notNull(column.getColumnType(), "列【 " + column.getColumnName()
				+ "】类型不能为空");
		Assert.notNull(column.getColumnLength(), "列【 " + column.getColumnName()
				+ "】长度不能为空");
	}

	@Override
	public void dropModelTable(int modelId) {
		Model model = getModel(modelId);
		dropModelTable(model);

		model.setCreated(false);
		dao.update(model, "created");
	}

	@Override
	public void dropModelTable(Model model) {
		dao.drop(model.getPhysicalName());
	}

	@Override
	public List<ModelColumn> getModelColumnList(int modelId) {
		return dao.query(ModelColumn.class, Cnd.where("modelId", "=", modelId));
	}

	@Override
	public ModelColumn getModelColumn(int modelId, String physicalName) {
		return dao.fetch(ModelColumn.class, Cnd.where("modelId", "=", modelId)
				.and("physicalName", "=", physicalName));
	}

	@Override
	public ModelColumn getModelColumn(int columnId) {
		return dao.fetch(ModelColumn.class, columnId);
	}

	@Override
	public List<ModelColumn> getModelColumn(int... columnIds) {
		Criteria cri = Cnd.cri();
		cri.where().andInIntArray("columnId", columnIds);
		return dao.query(ModelColumn.class, cri);
	}

	@Override
	public void addModelColumn(final ModelColumn column) {
		ModelColumn existColumn = getModelColumn(column.getModelId(),
				column.getPhysicalName());
		if (existColumn != null) {
			Assert.isNull(existColumn,
					"物理名称不能重复，重复的列是：" + existColumn.getColumnName());
		}
		dao.insert(column);
	}

	@Override
	public void deleteModelColumn(int columnId) {
		ModelColumn column = getModelColumn(columnId);

		if (column.isCreated()) {
			dropModelColumn(column);
		}

		dao.delete(ModelColumn.class, columnId);
	}

	private void deleteAllModelColumn(int modelId) {
		dao.clear(ModelColumn.class, Cnd.where("modelId", "=", modelId));
	}

	@Override
	public int getColumnCount(int modelId) {
		return dao.count(ModelColumn.class, Cnd.where("modelId", "=", modelId));
	}

	private int getBuiltColumnCount(int modelId) {
		List<ModelColumn> modelList = getModelColumnList(modelId);
		int i = 0;
		for (ModelColumn column : modelList) {
			if (column.isCreated()) {
				i++;
			}
		}
		return i;
	}

	@Override
	public void updateModelColumn(final ModelColumn column) {
		dao.update(column);
	}

	@Override
	public void buildModelColumn(ModelColumn... columns) {
		if (columns == null || columns.length == 0) {
			return;
		}

		Model model = getModel(columns[0].getModelId());
		Assert.isTrue(model.isCreated(), "模型对象还没有构建！");

		String sqlString = "";
		for (ModelColumn column : columns) {
			sqlString += "alter table `"
					+ model.getPhysicalName()
					+ "` add `"
					+ column.getPhysicalName()
					+ "` "
					+ column.getColumnType().getSqlType()
					+ "("
					+ column.getColumnLength()
					+ ") "
					+ (column.getDefaultValue() == null ? "" : "default "
							+ column.getDefaultValue()) + " "
					+ (column.isNullable() ? "null" : "not null" + ";\n");
		}
		Sql sql = Sqls.create(sqlString);
		dao.execute(sql);

		dao.update(columns, "created");
	}

	@Override
	public void buildModelColumn(int... columnId) {
		List<ModelColumn> columns = getModelColumn(columnId);
		if (columns != null && columns.size() > 0)
			buildModelColumn(columns.toArray(new ModelColumn[columns.size()]));
	}
	
	@Override
	public void rebuildModelColumn(String oldPhysicalColumnName,
			ModelColumn column) {
		Model model = getModel(column.getModelId());
		Assert.isTrue(model.isCreated(), "模型对象还没有构建！");
		String sqlString = "alter table `"
				+ model.getPhysicalName()
				+ "` change column `"
				+ oldPhysicalColumnName + "` `" + column.getPhysicalName()
				+ "` "
				+ column.getColumnType().getSqlType()
				+ "("
				+ column.getColumnLength()
				+ ") "
				+ (column.getDefaultValue() == null ? "" : "default "
						+ column.getDefaultValue()) + " "
				+ (column.isNullable() ? "null" : "not null" + ";\n");
		Sql sql = Sqls.create(sqlString);
		dao.execute(sql);
	}

	@Override
	public void dropModelColumn(ModelColumn column) {
		Assert.isTrue(column.isCreated(), "列" + column.getColumnName()
				+ "还没有构库！");
		Model model = getModel(column.getModelId());
		String sqlString = "alter table `" + model.getPhysicalName()
				+ "` drop `" + column.getPhysicalName() + "`";
		Sql sql = Sqls.create(sqlString);
		dao.execute(sql);
		
		column.setCreated(false);
		dao.update(column, "created");
	}

	@Override
	public void dropModelColumn(int columnId) {
		ModelColumn column = getModelColumn(columnId);
		dropModelColumn(column);
	}

}
